function AI () {
  this.step = ''
  // this.pattens = []
}

AI.prototype = {
  Pattern: {
    bottom: [
      'F` U` F',
      'R U R`',
      'R U U R` U` R U R` U`',
    ],
    top: {
      zxxy: 'R` U` R U` R` U U R',
      xyzx: 'R U R` U R U U R`',
      xzxz: 'R U R` U` R` F R F`',
      yzzx: 'F` R U R` U` R` F R',
      yzyz: 'F R U R` U` F`',
      xxxx: 'R R U U R U U R R',
      yxyx: 'F R U R` U` R U R` U` F`'
    },
    transform: {
      angle: {
        angle: 'R R B B R R',
        side: 'z z R` U R` B B R U` R',
        none: 'R U` R` U` F F U` R U R` U F F'
      },
      side: {
        angle: 'R` U R` B B R U` R',
        side: 'R R U` R R U U F F U` R R',
        none: 'U` R U U R` U` R U U L` U R` U` L'
      },
      none: {
        angle: 'z z R U` R` U` F F U` R U R` U F F',
        side: 'z z U` R U U R` U` R U U L` U R` U` L',
        none: ''
      }
    }
  },
  initWith (cube) {
    this.cube = new Cube()
    this.cube.clone(cube)
  },
  doStep (op) {
    this.cube.rotate(op)
    this.step += op + ' '
  },
  doPattern (ops) {
    let opList = ops.split(' ')
    for (let i = 0; i < opList.length; i++) {
      this.doStep(opList[i])
    }
  },
  finishBottomFace () {
    let bestFace = this.getBestFace()
    let bottomColor = bestFace.mostRecord

    this.setDown(bestFace.faceName) //将选好的面作为底面，并旋转
    let i = 0
    while (true) {
      if (this.isBottomFinished()) break
      if (!this.handleBottomWrongDirection(bottomColor)) {
        if (!this.handleBottomWrongColor(bottomColor)) throw new Error('未预料的异常')
      }
      if (this.handleTopWrongColor(bottomColor)) {
        let keyBlock = this.cube.getBlockByPosition(new Vector(1, 1, 1))
        let direction = keyBlock.color.getDirection(bottomColor)
        switch (direction) {
          case Dimension.y: {
            this.doPattern(this.Pattern.bottom[1])
            break
          }
          case Dimension.x: {
            this.doPattern(this.Pattern.bottom[0])
            break
          }
          case Dimension.z: {
            this.doPattern(this.Pattern.bottom[2])
            break
          }
        }
      } else this.doPattern(this.Pattern.bottom[1])
    }
  },
  finishTopFace () {
    //获取顶面颜色
    let topColor = Cube.getOppositeColor(this.cube.getBlockByPosition(new Vector(1, 1, -1)).color.z)
    let rotateTime = 0
    do {
      let topVector = this.getTopVector(topColor)
      if (typeof this.Pattern.top[topVector] !== 'undefined') {
        this.doPattern(this.Pattern.top[topVector])
      }
      this.doPattern('U')
    } while (rotateTime++ < 4)
  },
  transform () {
    let topType = this.getTransformType('up')
    let bottomType = this.getTransformType('down')
    // console.log(topType, bottomType)
    // this.pattens = [topType, bottomType]
    this.doPattern(this.Pattern.transform[topType][bottomType])
    while (this.cube.getBlockByPosition(new Vector(1, 1, 1)).color.x !== this.cube.getBlockByPosition(new Vector(1, 1, -1)).color.x) {
      this.doPattern('U')
    }
  },
  patternSimplify () {
    this.step = this.step.replace(/U U U U/, '')
    this.step = this.step.replace(/U U U/, 'U`')
    this.step = this.step.replace(/U U`/, '')
    this.step = this.step.replace(/U` U/, '')
  },
  getBestFace () {
    let faces = []
    let faceVector = ['up', 'down', 'left', 'right', 'front', 'behind']
    let up = this.cube.getFace('up')
    let down = this.cube.getFace('down')
    let left = this.cube.getFace('left')
    let right = this.cube.getFace('right')
    let front = this.cube.getFace('front')
    let behind = this.cube.getFace('behind')
    let faceDatas = [up, down, left, right, front, behind]
    for (let faceData of faceDatas) {
      let colorRecords = [0, 0, 0, 0, 0, 0, 0]
      for (let color of faceData) {
        colorRecords[color]++
      }
      let mostRecord = colorRecords[0]
      for (let record of colorRecords) {
        if (mostRecord < record) {
          mostRecord = record
        }
      }
      let colorName = colorRecords.indexOf(mostRecord)
      faces.push({
        faceName: faceVector[faceDatas.indexOf(faceData)],
        mostRecord: colorRecords.indexOf(mostRecord),
        num: mostRecord
      })
    }
    let bestFace = faces[0]
    for (let i = 1; i < faces.length; i++) {
      if (bestFace.num < faces[i].num) {
        bestFace = faces[i]
      }
    }
    return bestFace
  },
  setDown (faceName) {
    if (faceName === 'down') return
    let rule = {
      front: 'x`',
      behind: 'x',
      up: 'x x',
      left: 'z`',
      right: 'z'
    }
    this.doPattern(rule[faceName])
  },
  isBottomFinished () {
    let bottom = this.cube.getFace('down')
    for (let i = 1; i < bottom.length; i++) {
      if (bottom[i] !== bottom[0]) return false
    }
    return true
  },
  handleBottomWrongDirection (bottomColor) {
    let bottomLayer = this.cube.getLayer('down')
    for (let block of bottomLayer) {
      let blockDirection = block.color.getDirection(bottomColor)
      if (blockDirection === null || blockDirection === Dimension.z) continue
      let currentPostion = block.position
      if (currentPostion.y === -1 && currentPostion.x === 1) {
        this.doStep('D')
      }
      if (currentPostion.y === -1 && currentPostion.x === -1) {
        this.doStep('D')
        this.doStep('D')
      }
      if (currentPostion.y === 1 && currentPostion.x === -1) {
        this.doStep('D`')
      }
      return true
    }
    return false
  },
  handleTopWrongColor (bottomColor) {
    let topLayer = this.cube.getLayer('up')
    for (let block of topLayer) {
      let blockDirection = block.color.getDirection(bottomColor)
      if (blockDirection === null) continue
      let currentPosition = block.position
      if (currentPosition.y === -1 && currentPosition.x === 1) {
        this.doStep('U`')
      }
      if (currentPosition.y === -1 && currentPosition.x === -1) {
        this.doStep('U')
        this.doStep('U')
      }
      if (currentPosition.y === 1 && currentPosition.x === -1) {
        this.doStep('U')
      }
      return true
    }
    return false
  },
  handleBottomWrongColor (bottomColor) {
    let bottomLayer = this.cube.getLayer('down')
    for (let block of bottomLayer) {
      let blockDirection = block.color.getDirection(bottomColor)
      if (blockDirection !== null) continue
      let currentPosition = block.position
      if (currentPosition.y === -1 && currentPosition.x === 1) {
        this.doStep('D')
      }
      if (currentPosition.y === -1 && currentPosition.x === -1) {
        this.doStep('D')
        this.doStep('D')
      }
      if (currentPosition.y === 1 && currentPosition.x === -1) {
        this.doStep('D`')
      }
      return true
    }
    return false
  },
  getTopVector (topColor) {
    let vector = ['', 'x', 'y', 'z']
    return vector[this.cube.getBlockByPosition(new Vector(-1, -1, 1)).color.getDirection(topColor)] +
      vector[this.cube.getBlockByPosition(new Vector(-1, 1, 1)).color.getDirection(topColor)] +
      vector[this.cube.getBlockByPosition(new Vector(1, -1, 1)).color.getDirection(topColor)] +
      vector[this.cube.getBlockByPosition(new Vector(1, 1, 1)).color.getDirection(topColor)]
  },
  getTransformType (layerName) {
    let layer = this.cube.getLayer(layerName)
    let sides = {
      front: [layer[2].color.x, layer[3].color.x],
      behind: [layer[0].color.x, layer[1].color.x],
      left: [layer[0].color.y, layer[2].color.y],
      right: [layer[1].color.y, layer[3].color.y]
    }
    let noTransform = true
    for (let key in sides) {
      if (sides[key][0] !== sides[key][1])
        noTransform = false
    }
    if (noTransform) return 'none'
    for (let key in sides) {
      let side = sides[key]
      if (side[0] === side[1]) {
        if (side === sides.left && layerName === 'up') this.doPattern('U')
        if (side === sides.right && layerName === 'up') this.doPattern('U`')
        if (side === sides.front && layerName === 'up') this.doPattern('U U')
        if (side === sides.left && layerName === 'down') this.doPattern('D`')
        if (side === sides.right && layerName === 'down') this.doPattern('D')
        if (side === sides.front && layerName === 'down') this.doPattern('D D')
        return 'side'
      }
    }
    return 'angle'
  },
  recover () {
    this.finishBottomFace()
    this.finishTopFace()
    this.transform()
    this.patternSimplify()
  }
}